package com.huwaiwai.lock.reentrantreadwritelock;


import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;

/**
 * Created by hww on 2018/6/11 下午2:04.
 */
public class MyReentrantReadWriteLock implements ReadWriteLock, Serializable {

    private static final long serialVersionUID = -6068114258246577597L;

    private final MyReentrantReadWriteLock.ReadLock readerLock;

    private final MyReentrantReadWriteLock.WriteLock writerLock;

    final Sync sync;

    public MyReentrantReadWriteLock() {
        this(false);
    }

    public MyReentrantReadWriteLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
        readerLock = new ReadLock(this);
        writerLock = new WriteLock(this);
    }

    public MyReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }
    public MyReentrantReadWriteLock.ReadLock  readLock()  { return readerLock; }


    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 7620490565439870390L;
        /**
         * 读写锁将AQS里面的int类型的状态值分成了高16位和低16位，分别表示读、写锁的状态
         */
        static final int SHARED_SHIFT = 16;
        /**
         * 读锁的状态单元 读锁+1 相当于 加了2^16
         */
        static final int SHARED_UNIT = 1 << SHARED_SHIFT;
        /**
         * 读写状态的最大值为 2^16 - 1;
         */
        static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
        /**
         * 写锁的掩码
         */
        static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;

        /**
         * 获取读锁的持有数
         */
        static int sharedCount(int c) {
            return c >>> SHARED_SHIFT;
        }

        /**
         * 获取写锁的持有数
         */
        static int exclusiveCount(int c) {
            return c & EXCLUSIVE_MASK;
        }

        /**
         * 线程重入计数器
         */
        static final class HoldCounter {
            int count = 0;
            //使用线程id 而不是线程引用 是为了帮助垃圾回收
            final long tid = getThreadId(Thread.currentThread());
        }

        /**
         * 重写了init方法
         * 在第一次调用get()方法时 若threadLocal中没有值
         * 会调用此初始化方法
         * 减少了一次判断 是否存在的逻辑
         */
        static final class ThreadLocalHoldCounter extends ThreadLocal<HoldCounter> {
            public HoldCounter initialValue() {
                return new HoldCounter();
            }
        }

        /** 每个线程持有的重入读锁的计数器 当count降为0时删除 */
        private transient ThreadLocalHoldCounter readHolds;

        /**
         * 保存了最后一个获取读锁的重入计数器
         */
        private transient HoldCounter cachedHoldCounter;

        private transient Thread firstReader = null;
        private transient int firstReaderHoldCount;

        Sync() {
            readHolds = new ThreadLocalHoldCounter();
            setState(getState()); // ensures visibility of readHolds
        }

        /**
         * 读锁是否需要被阻塞
         * 留给子类实现，用于实现公平/非公平 语义
         * @return
         */
        abstract boolean readerShouldBlock();

        /**
         * 写锁是否需要被阻塞
         * 留给子类实现，用于实现公平/非公平 语义
         * @return
         */
        abstract boolean writeShouldBlock();

        /**
         * 写锁(独占锁)获取
         * @param acquires
         * @return
         */
        protected final boolean tryAcquire(int acquires) {
            Thread current = Thread.currentThread();
            int c = getState();
            int w = exclusiveCount(c);
            if (c != 0) {
                //有人占用锁
                if (w == 0 || current != getExclusiveOwnerThread()) {
                    //写锁无人占用(读锁被占用) 或 占用写锁的不是当前线程  返回失败
                    return false;
                }
                if (w + exclusiveCount(acquires) > MAX_COUNT) {
                    //写锁占有已达上限
                    throw new Error("Maximum lock count exceeded");
                }
                //更新AQS 内部状态值
                setState(c + acquires);
                return true;
            }
            //锁空闲状态
            if (writeShouldBlock() || !compareAndSetState(c, c + acquires)) {
                //写锁需要阻塞(由子类实现此方法 根据公平策略而定) 或 更新AQS状态失败
                return false;
            }
            setExclusiveOwnerThread(current);
            return true;
        }

        /**
         * 写锁(独占锁)释放
         * @param releases
         * @return
         */
        protected final boolean tryRelease(int releases) {
            if (!isHeldExclusively()) {
                //理论上释放锁的是当前占有锁的线程 若不是抛出异常
                throw new IllegalMonitorStateException();
            }
            int nextc = getState() - releases;
            boolean free = exclusiveCount(nextc) == 0;
            if (free) {
                //释放完了所有锁
                setExclusiveOwnerThread(null);
            }
            //更新AQS状态值
            setState(nextc);
            return free;
        }

        /**
         * 读锁(共享锁)获取
         * @param unused
         * @return
         */
        protected final int tryAcquireShared(int unused) {
            Thread current = Thread.currentThread();
            int c = getState();
            if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current) {
                //写锁被占用 且不是当前线程 返回失败
                //此处实现了 占用了写锁的线程 可以占用读锁(所谓的锁降级)
                return -1;
            }

            int r = sharedCount(c);
            if (!readerShouldBlock() && r < MAX_COUNT && compareAndSetState(c, c + SHARED_UNIT)) {
                //读锁不被阻塞 并且 当前占有数小于最大值 并且 更新状态成功
                if (r == 0) {
                    //之前锁空闲状态 也就是说当前线程是第一个拿到读锁的线程
                    firstReader = current;
                    firstReaderHoldCount = 1;
                } else if (firstReader == current) {
                    //之前已经有线程拿到读锁 但是当前线程是第一个拿到锁的线程
                    firstReaderHoldCount++;
                } else {
                    //之前已经有线程拿到读锁 且不是当前线程
                    HoldCounter rh = cachedHoldCounter;
                    if (rh == null || rh.tid != getThreadId(current)) {
                        //最后一次获得读锁的线程为空 或者 不是当前线程 则将当前线程的计数器设置为缓存的计数器
                        cachedHoldCounter = rh = readHolds.get();
                    } else if (rh.count == 0) {
                        //缓存的计数器 就是当前线程的计数器 而且是第一次重入 把引用设置到ThreadLocal中
                        readHolds.set(rh);
                    }
                    rh.count++;
                }
                //成功获取了读锁
                return 1;
            }
            return fullTryAcquireShared(current);
        }

        /**
         * 无限循环获取读锁
         * 此方法可以循环 CAS失败的情况
         * @param current
         * @return
         */
        final int fullTryAcquireShared(Thread current) {
            HoldCounter rh = null;
            for (;;) {
                int c = getState();
                if (exclusiveCount(c) != 0) {
                    //写(独占)锁被占用
                    if (getExclusiveOwnerThread() != current) {
                        //占用写锁的不是当前线程
                        return -1;
                    }
                } else if (readerShouldBlock()) {
                    //读线程需要被阻塞
                    if (firstReader == current) {
                        //当前线程是第一个获取读锁的线程
                    } else {
                        //当前线程不是第一个获取读锁的线程
                        if (rh == null) {
                            rh = cachedHoldCounter;
                            if (rh == null || rh.tid != getThreadId(current)) {
                                //最后一个获取读锁的线程为空(当前只有一个线程获取读锁) 或者不是当前线程
                                rh = readHolds.get();
                                if (rh.count == 0) {
                                    //当前线程之前没有占有读锁(即非重入状态) 清除线程缓存中的计数器
                                    readHolds.remove();
                                }
                            }
                        }
                        if (rh.count == 0) {
                            //当前线程非重入 需要被阻塞 获取锁失败
                            return -1;
                        }
                    }
                }
                if (sharedCount(c) == MAX_COUNT) {
                    //锁已经到了最大值
                    throw new Error("Maximum lock count exceeded");
                }
                if (compareAndSetState(c, c + SHARED_UNIT)) {
                    //更新AQS状态成功 流程类似 tryAcquireShared 中的流程不做注释了
                    if (sharedCount(c) == 0) {
                        firstReader = current;
                        firstReaderHoldCount = 1;
                    } else if (firstReader == current) {
                        firstReaderHoldCount++;
                    } else {
                        if (rh == null) {
                            rh = cachedHoldCounter;
                        }
                        if (rh == null || rh.tid != getThreadId(current)) {
                            rh = readHolds.get();
                        } else if (rh.count == 0) {
                            readHolds.set(rh);
                        }
                        rh.count++;
                        cachedHoldCounter = rh;
                    }
                    return 1;
                }
            }
        }

        /**
         * 释放读锁
         * @param unused
         * @return
         */
        protected final boolean tryReleaseShared(int unused) {
            Thread current = Thread.currentThread();
            if (firstReader == current) {
                //当前线程是第一个获取读锁的线程
                if (firstReaderHoldCount == 1) {
                    //只持有一次锁，也就是未重入 释放
                    firstReader = null;
                } else {
                    //是重入读锁 释放一次 计数器减1
                    firstReaderHoldCount--;
                }
            } else {
                //当前线程不是第一个获取读锁的线程
                HoldCounter rh = cachedHoldCounter;
                if (rh == null || rh.tid != getThreadId(current)) {
                    //当前线程也不是最后一个获取读锁的线程  从threadLocal中获取锁计数器
                    rh = readHolds.get();
                }
                int count = rh.count;
                if (count <= 1) {
                    //计数器小于等于1 说明当前线程没有重入操作 可以释放
                    readHolds.remove();
                    if (count <= 0) {
                        //计数器小于等于0 这是不应该存在的情况 类似于没有获取读锁的线程调用了释放锁的方法
                        throw unmatchedUnlockException();
                    }
                }
                //计数器大于1 说明是重入读锁 计数器减一
                --rh.count;
            }
            for (;;) {
                //无限循环更新AQS状态  直到更新成功
                int c = getState();
                int nextc = c - SHARED_UNIT;
                if (compareAndSetState(c, nextc)) {
                    return nextc == 0;
                }
            }
        }

        private IllegalMonitorStateException unmatchedUnlockException() {
            return new IllegalMonitorStateException(
                    "attempt to unlock read lock, not locked by current thread");
        }

        /**
         * 尝试获取写锁
         * @return
         */
        final boolean tryWriteLock() {
            Thread current = Thread.currentThread();
            int c = getState();
            if (c != 0) {
                //占用锁状态
                int w = exclusiveCount(c);
                if (w == 0 || current != getExclusiveOwnerThread()) {
                    //写锁空闲(读锁被占用) 或者 占用写锁的不是当前线程 返回失败
                    return false;
                }
                if (w == MAX_COUNT) {
                    //写锁已经是最大占有数了
                    throw new Error("Maximum lock count exceeded");
                }
            }
            //锁空闲 或者 当前线程是写锁重入
            if (!compareAndSetState(c, c + 1)) {
                //CAS更新AQS状态值失败
                return false;
            }
            //获取锁成功
            setExclusiveOwnerThread(current);
            return true;
        }

        /**
         * 尝试获取读锁
         * @return
         */
        final boolean tryReadLock() {
            Thread current = Thread.currentThread();
            //无限循环的是 CAS失败的情况
            for (;;) {
                int c = getState();
                if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current) {
                    //写锁被占用 且不是当前线程 (读写互斥) 失败
                    return false;
                }
                int r = sharedCount(c);
                if (r == MAX_COUNT) {
                    //读锁已经达到最大占有数
                    throw new Error("Maximum lock count exceeded");
                }
                //开始cas修改AQS锁状态
                if (compareAndSetState(c, c + SHARED_SHIFT)) {
                    if (r == 0) {
                        //读锁未被占用  也就是说当前线程是第一个占有读锁的线程 缓存到firstReader上 并计数
                        firstReader = current;
                        firstReaderHoldCount++;
                    } else if (firstReader == current) {
                        //读锁有占用，但是当前线程是第一个占用读锁的线程  增加重入计数
                        firstReaderHoldCount++;
                    } else {
                        //当前线程不是第一个占用读锁的线程 获取最后一次占用读锁的线程
                        HoldCounter rh = cachedHoldCounter;
                        if (rh == null || rh.tid != getThreadId(current)) {
                            //最后一次占用的线程为空（说明当前只有一个线程占用读锁）或者 最后一次占用读锁的线程不是当前线程
                            //将当前线程设置为最后一次占用读锁的线程
                            cachedHoldCounter = rh = readHolds.get();
                        } else if (rh.count == 0) {
                            //当前线程不是重入状态 将计数器设置到线程本地变量中
                            readHolds.set(rh);
                        }
                        //读锁计数器+1
                        rh.count++;
                    }
                    return true;
                }
            }
        }

        /**
         * 判断当前线程是否是占有独享锁的线程
         * @return
         */
        protected final boolean isHeldExclusively() {
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

        /**
         * 创建条件
         * @return
         */
        final ConditionObject newCondition() {
            return new ConditionObject();
        }

        /**
         * 获取占用独享锁的线程
         * @return
         */
        final Thread getOwner() {
            return exclusiveCount(getState()) == 0 ? null : getExclusiveOwnerThread();
        }

        /**
         * 占用读锁的线程数
         * @return
         */
        final int getReadLockCount() {
            return sharedCount(getState());
        }

        /**
         * 写锁是否被占用
         * @return
         */
        final boolean isWriteLocked() {
            return exclusiveCount(getState()) != 0;
        }

        /**
         * 写锁重入次数
         * @return
         */
        final int getWriteHoldCount() {
            return isHeldExclusively() ? exclusiveCount(getState()) : 0;
        }

        /**
         * 当前线程的读锁重入次数
         * @return
         */
        final int getReadHoldCount() {
            if (getReadLockCount() == 0) {
                //读锁未被占用
                return 0;
            }
            Thread current = Thread.currentThread();
            if (firstReader == current) {
                //当前线程是第一个占有读锁的线程 直接取对应的计数器
                return firstReaderHoldCount;
            }
            HoldCounter rh = cachedHoldCounter;
            if (rh != null && rh.tid == getThreadId(current)) {
                //当前线程是最后一个占有读锁的线程  直接取对应的计数器
                return rh.count;
            }
            //从线程本地变量中获取重入计数器
            int count = readHolds.get().count;
            if (count == 0) {
                //若计数器为0 即当前线程未占用读锁 则删除本地变量中的计数器
                //todo 不知道什么用意
                readHolds.remove();
            }
            return count;
        }

        /**
         * 反序列化 实例
         * @param s
         * @throws IOException
         * @throws ClassNotFoundException
         */
        private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
            s.defaultReadObject();
            readHolds = new ThreadLocalHoldCounter();
            setState(0);
        }

        /**
         * 返回AQS的状态
         * @return
         */
        final int getCount() {
            return getState();
        }
    }

    /**
     * 非公平锁
     */
    static final class NonfairSync extends Sync {
        @Override
        boolean readerShouldBlock() {
            //由于包权限 此处不能引用AQS中的Node对象
            //此处的逻辑大致是这样的
            //同时满足下面四点 才会返回true 线程才会被阻塞
            //1.AQS中head结点不为空
            //2.head结点的后驱结点s不为空
            //3.s结点是请求写锁的线程封装的结点
            //4.s结点的线程属性不为空
            return false;
        }

        @Override
        boolean writeShouldBlock() {
            return false;
        }
    }

    /**
     * 公平锁
     */
    static final class FairSync extends Sync{
        @Override
        boolean readerShouldBlock() {
            //等待队列中是否有线程  不让插队
            return hasQueuedPredecessors();
        }
        @Override
        boolean writeShouldBlock() {
            //等待队列中是否有线程  不让插队
            return hasQueuedPredecessors();
        }
    }

    public static class ReadLock implements Lock, Serializable {

        private final Sync sync;

        protected  ReadLock (MyReentrantReadWriteLock lock) {
            sync = lock.sync;
        }

        @Override
        public void lock() {
            sync.acquireShared(1);
        }

        @Override
        public void lockInterruptibly() throws InterruptedException {
            sync.acquireSharedInterruptibly(1);
        }

        @Override
        public boolean tryLock() {
            return sync.tryReadLock();
        }

        @Override
        public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
            return sync.tryAcquireSharedNanos(1, unit.toNanos(time));
        }

        @Override
        public void unlock() {
            sync.releaseShared(1);
        }
        @Override
        public Condition newCondition() {
            throw new UnsupportedOperationException();
        }

        public String toString() {
            int r = sync.getReadLockCount();
            return super.toString() +
                    "[Read locks = " + r + "]";
        }

    }

    public static class WriteLock implements Lock, Serializable {

        private final Sync sync;

        public WriteLock(MyReentrantReadWriteLock lock) {
            sync = lock.sync;
        }

        @Override
        public void lock() {
            sync.acquire(1);
        }

        @Override
        public void lockInterruptibly() throws InterruptedException {
            sync.acquireInterruptibly(1);
        }

        @Override
        public boolean tryLock() {
            return sync.tryWriteLock();
        }

        @Override
        public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
            return sync.tryAcquireNanos(1, unit.toNanos(time));
        }

        /**
         * Releases the lock.
         * <p>
         * <p><b>Implementation Considerations</b>
         * <p>
         * <p>A {@code Lock} implementation will usually impose
         * restrictions on which thread can release a lock (typically only the
         * holder of the lock can release it) and may throw
         * an (unchecked) exception if the restriction is violated.
         * Any restrictions and the exception
         * type must be documented by that {@code Lock} implementation.
         */
        @Override
        public void unlock() {
            sync.release(1);
        }

        /**
         * Returns a new {@link Condition} instance that is bound to this
         * {@code Lock} instance.
         * <p>
         * <p>Before waiting on the condition the lock must be held by the
         * current thread.
         * A call to {@link Condition#await()} will atomically release the lock
         * before waiting and re-acquire the lock before the wait returns.
         * <p>
         * <p><b>Implementation Considerations</b>
         * <p>
         * <p>The exact operation of the {@link Condition} instance depends on
         * the {@code Lock} implementation and must be documented by that
         * implementation.
         *
         * @return A new {@link Condition} instance for this {@code Lock} instance
         * @throws UnsupportedOperationException if this {@code Lock}
         *                                       implementation does not support conditions
         */
        @Override
        public Condition newCondition() {
            return sync.newCondition();
        }

        public String toString() {
            Thread o = sync.getOwner();
            return super.toString() + ((o == null) ?
                    "[Unlocked]" :
                    "[Locked by thread " + o.getName() + "]");
        }

        public boolean isHeldByCurrentThread() {
            return sync.isHeldExclusively();
        }

        public int getHoldCount() {
            return sync.getWriteHoldCount();
        }
    }

    public final boolean isFair() {
        return sync instanceof FairSync;
    }

    protected Thread getOwner() {
        return sync.getOwner();
    }

    public int getReadLockCount() {
        return sync.getReadLockCount();
    }

    public boolean isWriteLocked() {
        return sync.isWriteLocked();
    }

    public boolean isWriteLockedByCurrentThread() {
        return sync.isHeldExclusively();
    }

    public int getWriteHoldCount() {
        return sync.getWriteHoldCount();
    }

    public int getReadHoldCount() {
        return sync.getReadHoldCount();
    }

    protected Collection<Thread> getQueuedWriterThreads() {
        return sync.getExclusiveQueuedThreads();
    }

    protected Collection<Thread> getQueuedReaderThreads() {
        return sync.getSharedQueuedThreads();
    }

    public final boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }

    public final boolean hasQueuedThread(Thread thread) {
        return sync.isQueued(thread);
    }

    public final int getQueueLength() {
        return sync.getQueueLength();
    }

    protected Collection<Thread> getQueuedThreads() {
        return sync.getQueuedThreads();
    }

    public boolean hasWaiters(Condition condition) {
        if (condition == null)
            throw new NullPointerException();
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
    }

    public int getWaitQueueLength(Condition condition) {
        if (condition == null)
            throw new NullPointerException();
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
    }

    protected Collection<Thread> getWaitingThreads(Condition condition) {
        if (condition == null)
            throw new NullPointerException();
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
    }

    public String toString() {
        int c = sync.getCount();
        int w = Sync.exclusiveCount(c);
        int r = Sync.sharedCount(c);

        return super.toString() +
                "[Write locks = " + w + ", Read locks = " + r + "]";
    }

    static final long getThreadId(Thread thread) {
        return UNSAFE.getLongVolatile(thread, TID_OFFSET);
    }

    // Unsafe mechanics
    private static final sun.misc.Unsafe UNSAFE;
    private static final long TID_OFFSET;
    static {
        try {
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            Class<?> tk = Thread.class;
            TID_OFFSET = UNSAFE.objectFieldOffset
                    (tk.getDeclaredField("tid"));
        } catch (Exception e) {
            throw new Error(e);
        }
    }


}
